package my.soft.aiteacher.config;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.jsonwebtoken.Claims;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import my.soft.aiteacher.common.mapper.TbPermissionsMapper;
import my.soft.aiteacher.common.mapper.TbRolePermissionsMapper;
import my.soft.aiteacher.common.mapper.TbUserRolesMapper;
import my.soft.aiteacher.common.mapper.UserMapper;
import my.soft.aiteacher.exception.BusinessException;
import my.soft.aiteacher.common.pojo.TbPermissions;
import my.soft.aiteacher.common.pojo.TbRolePermissions;
import my.soft.aiteacher.common.pojo.TbUserRoles;
import my.soft.aiteacher.common.pojo.UserDo;
import my.soft.aiteacher.utils.JWTUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.List;
import java.util.Objects;

@Component
@Slf4j
public class AuthorizationFillterChain extends OncePerRequestFilter {
    @Resource
    private UserMapper userMapper;
    @Resource
    private TbPermissionsMapper tbPermissionsMapper;
    @Resource
    private TbRolePermissionsMapper tbRolePermissionsMapper;
    @Resource
    private TbUserRolesMapper tbUserRolesMapper;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            String path = request.getRequestURI();
            if (path.equals("/user/login") || path.equals("/videoInformation/page") || path.startsWith("/video/getVideo/") || path.equals("/user/mailLogin") || path.equals("/user/sendMail") || path.equals("/error") || path.startsWith("/doc.html") || path.startsWith("/webjars/") ||
                    path.startsWith("/v3/api-docs") || path.startsWith("/swagger-resources") || path.equals("/user/getCaptcha")) {
                filterChain.doFilter(request, response);
                return;
            }

            String authorization = request.getHeader("Authorization");
            if (Objects.isNull(authorization)) {
                throw new BusinessException("未携带token");
            }
            Claims claims = JWTUtils.verifyToken(authorization);
            if (Objects.isNull(claims)) {
                throw new BusinessException("身份信息有误，请联系管理员");
            }
            String username = (String) claims.get("username");
            Long userId = userMapper.selectOne(new QueryWrapper<UserDo>().select("id").eq("username", username)).getId();

            List<Integer> roleIds = tbUserRolesMapper.selectList(new QueryWrapper<TbUserRoles>()
                            .select("role_id")
                            .eq("user_id", userId))
                    .stream()
                    .map(TbUserRoles::getRoleId)
                    .toList();

            List<Integer> permissionIds = tbRolePermissionsMapper.selectList(new QueryWrapper<TbRolePermissions>()
                            .in("role_id", roleIds)
                            .select("permission_id"))
                    .stream()
                    .map(TbRolePermissions::getPermissionId)
                    .toList();

            List<String> permissionCodes = tbPermissionsMapper.selectList(new QueryWrapper<TbPermissions>()
                                    .select("permission_code")
                                    .in("permission_id", permissionIds))
                    .stream()
                    .map(TbPermissions::getPermissionCode)
                    .toList();
            log.info("当前登录用户：{}，权限列表：{}", username, permissionCodes);
            List<SimpleGrantedAuthority> credentialsList = permissionCodes.stream().map(SimpleGrantedAuthority::new).toList();
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(claims.get("username"), null, credentialsList);
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            filterChain.doFilter(request, response);
        } catch (BusinessException e) {
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(HttpServletResponse.SC_OK);
            response.getWriter().write(
                    String.format("{\"code\":401,\"message\":\"%s\",\"data\":null}", e.getMessage())
            );
        }
    }
}
